package com.ai.filter;


import com.ai.common.constant.RedisConstants;
import com.ai.config.security.handler.CustomizeAuthenticationEntryPoint;
import com.ai.entity.security.SysUser;
import com.ai.util.JwtUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Author jiaok
 * @Date 2023/5/9 11:14
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private CustomizeAuthenticationEntryPoint failedAuthenticationEntryPoint;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //从请求头中获取token字段
            String token = request.getHeader("Authorization");
        if (StringUtils.isBlank(token)){
            if (("/thickSteel/user/login").equals(request.getRequestURI())&&request.getMethod().equals("POST")) {
                //登录请求，直接放行
                log.info("=========================== 进入登录接口  ===========================");
                log.info("===========================  接收到请求，token为 {}  ===========================",token);

                filterChain.doFilter(request,response);
                /**
                 *   如果这里不return，请求虽然经过了上面的放行操作，
                 *   但请求经过后面的过滤器处理结束之后，还是会回到这里，如果不return，
                 *    就会执行后面的内容，但是我们不需要他执行后面的代码，所以就return掉
                 */
                return;
            } else if (request.getRequestURI().contains("/thickSteel/algorithmAPI")) {
//                log.info("=========================== 进入算法接口  ===========================");
                //算法接口，全部放行
                filterChain.doFilter(request,response);
                return;
            } else if (request.getRequestURI().equals("/thickSteel/ws")) {
//                log.info("===========================  进入websocket接口  ===========================");
                filterChain.doFilter(request,response);
                return;
            } else {
                log.error("未携带Token");
                //为携带token，却想要访问其他的功能页面，痴心妄想，打回
                failedAuthenticationEntryPoint.commence(request,response,new DisabledException("请登录后重新访问"));
            }
        }

        try {
            Claims parseJWT = JwtUtil.parseJWT(token);
            String userId = parseJWT.getSubject();
            log.debug("-------------------------  当前登录用户id"+ userId +"  -------------------------");
            //从redis中获取
            String userInfo = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_USER_INFO + userId);
            if (!StringUtils.isBlank(userInfo)){
                SysUser sysUser = JSON.parseObject(userInfo, SysUser.class);
                //防止非法token
                if (Objects.isNull(sysUser)){
                    failedAuthenticationEntryPoint.commence(request,response,new DisabledException("请登录后重新访问"));
                }
                ArrayList<GrantedAuthority> grantedAuthorityArrayList = new ArrayList<>();
                //先转换为jsonObject对象，便于获取权限部分信息
                JSONObject jsonObject = JSONObject.parseObject(userInfo);
                List<Map<String,String>> grantedAuthorities= (List<Map<String, String>>) jsonObject.get("grantedAuthorities");

                for (Map<String, String> grantedAuthority : grantedAuthorities) {
                    //查找出所有當前登录的权限
                    for (Map.Entry<String, String> entry  : grantedAuthority.entrySet()) {
                        if (entry.getKey().equals("authority")){
                            grantedAuthorityArrayList.add(new SimpleGrantedAuthority(entry.getValue()));
                        }
                    }
                }
                sysUser.setGrantedAuthorities(grantedAuthorityArrayList);
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                       new UsernamePasswordAuthenticationToken(sysUser, null, sysUser.getGrantedAuthorities());
                //将用户信息存储在SecurityContextHolder中，从而避免后续的重复认证
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                filterChain.doFilter(request,response);
           }else {
                failedAuthenticationEntryPoint.commence(request,response,new DisabledException("请登录后重新访问"));
            }
        } catch (Exception e) {
            log.error("Token过期");
            failedAuthenticationEntryPoint.commence(request,response,new DisabledException("token过期，请重新登录"));
        }

    }
}
